home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue34 / timetrav / BaseDate.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-03-25  |  22.9 KB  |  641 lines

  1. unit BaseDate;
  2. interface
  3. uses classes, sysutils, calConstants;
  4.  
  5. ResourceString
  6.   cNoSuchMonthIndex = 'Month # %d does not exist';
  7.   cNoSuchDayIndex = 'Day # %d does not exist';
  8.   cNoLeapYearFunction = 'No Leap Year Formula';
  9.   cNoEncodeDateProc = 'No Encode Date Proc';
  10.   cNoDecodeDateProc = 'No Decode Date Proc';
  11.   cMJDOutsideTDateTimeRange = 'MJD outside TDateTime Range';
  12.   cDayOutOfMonthRange = 'Day out of month''s range';
  13.   cMonthOutOfYearRange = 'Month out of year''s range';
  14.   c1752isChangeOver = '3-13 Sept, 1752, do not exist';
  15.   cOutOfYearRange = 'Only good for %s BC to %s AD';
  16.   cOutOfMJDRange = 'MJD limited to %n through %n';
  17.  
  18. Type
  19.   EMonthList = exception;
  20.   EDayList = exception;
  21.   ENoLeapYearFunction = exception;
  22.   ENoEncodeDateProc = exception;
  23.   ENoDecodeDateProc = exception;
  24.   EMJDOutsideTDateTimeRange = exception;
  25.   eDayOutOfMonthRange = exception;
  26.   eMonthOutOfYearRange = exception;
  27.   eChangeOverError = exception;
  28.   eOutOfYEarRange = exception;
  29.   eOutOfMJDRange = exception;
  30.  
  31.   TCalendarDate = record
  32.                     Year, Month, Day : integer;
  33.                     end;
  34.   TMJD = double;  // this in effect replaces TDateTime
  35.   TLinkDate = record  //a date in the current calendar and its MJD equivalent
  36.                 Date : tCalendarDate;
  37.                 MJD : TMJD;
  38.                 end;
  39.   TGregorianChangeRec = record
  40.                 LastMJD : TMJD;        // Last Date in MJD value
  41.                 LastDate : tCalendarDate;  // Last date in old system
  42.                 Adjustment : integer;  // days +/- to add/delete to/from calendar
  43.                                        // day of month/year + adjustment = first date Gregorian system in use
  44.                 end;
  45.   TmonthStructure = class
  46.     private
  47.       fNumDays : integer;
  48.       fName : string;
  49.       fMissingDaysStart,
  50.       fMissingDaysEnd : integer;
  51.     public
  52.       constructor BuildMonth(const aName : string; const aNumDays, StartMissing, EndMissing : integer);
  53.       function HasMissingDays(var First, Last : integer): boolean;
  54.       Property NumDays : integer read fNumDays write fNumdays;
  55.       property Name : string read fName write fName;
  56.       Property FirstMissingDay : integer read fMissingDaysStart write fMissingDaysStart;
  57.       Property LastMissingDay : integer read fMissingDaysEnd write fMissingDaysEnd;
  58.     end;
  59.  
  60.   TYearStructure = class
  61.     private
  62.       fNumMonths : integer;
  63.       fMonthList : tlist;
  64.       procedure GrowMonthList;
  65.     protected
  66.       function GetMonthName(index : integer): string;
  67.       procedure SetMonthName(index : integer; aName : string);
  68.       function GetMonthLen(index : integer): integer;
  69.       procedure SetMonthLen(index : integer; aLen : integer);
  70.       function GetMonthStruc(index : integer): tMonthStructure;
  71.       procedure setMonthStruc(index : integer; aStruc : tMonthStructure);
  72.     public
  73.       constructor create;
  74.       destructor destroy; override;
  75. //      Procedure SwapMonths(index : integer; var WithMonth : tMonthStructure);
  76.       property NumMonths : integer read fNumMonths write fNumMonths;
  77.       property MonthName[index : integer] : string read getMonthName write setMonthName;
  78.       Property MonthLen[index : integer] : integer read getMonthLen write setMonthLen;
  79.       Property MonthObj[index : integer] : tMonthStructure read getMonthStruc write setMonthStruc;
  80.       end;
  81.  
  82. //  TLeapYearRule = function(aYear : integer): boolean of object;
  83. //  TEncodeDateProc = procedure(var MJD : TMJD; const aYear, aMonth, aDay :integer) of object;
  84. //  TDecodeDateProc = procedure(const MJD : TMJD; var aYear, aMonth, aDay :integer) of object;
  85.  
  86.   TCalendarDef = class
  87.    Private
  88.     fName : string;                  // name, e.g. English, Swedish, Roman
  89.     fDate : TLinkDate;               // Date we are currently working with
  90.     fAstro : boolean;                // set true to insert a year zero between 1BC and 1AD
  91.     fYearDef : TYearStructure;
  92.     fDayName : TStringlist;          // count is the number of days per week
  93.     fDayStart : double;              // 0.0 = midnight, 0.5 = noon, etc.
  94. //    fIsLeapYear : tLeapYearRule;
  95. //    fOnEncode : tEncodeDateProc;
  96. //    fOnDecode : tDecodeDateProc;
  97.     fAlignmentDate : TLinkDate;
  98.     fNameOfPreviousSystem : string;   // name of calendar system before fGregorian date
  99.     fGregorianDate : TGregorianChangeRec;
  100.     fSwitchOnChangeDate : boolean;    // true means use previous system for dates before Gegorian dates
  101.    Protected
  102.     function getDate : TLinkDate; virtual;
  103.     procedure setDate(avalue : tLinkDate); virtual;
  104.     function getDaysPerYear : cardinal; virtual;
  105. //    procedure setDaysPerYear(avalue : cardinal); virtual;
  106.     function getNumberOfMonths : integer; virtual;
  107.     procedure setNumberOfMonths(avalue : integer); virtual;
  108.     function getMonthName(index: integer): string; virtual;
  109.     procedure setMonthName(index : integer; aName : string);  virtual;
  110.     function getMonthLength(index : integer): cardinal; virtual;
  111.     procedure setMonthLength(index : integer; aValue : cardinal); virtual;
  112.     function getDayName(index : integer): string; virtual;
  113.     procedure setDayName(index : integer; aName : string); virtual;
  114.     function getDayStart: double; virtual;
  115.     procedure setDayStart(avalue : double); virtual;
  116. //    Procedure fEncodeDate(var MJD : TMJD; const aYear, aMonth, aDay :integer); virtual;  abstract;
  117. //    Procedure fDecodeDate(const MJD : TMJD; var aYear, aMonth, aDay :integer); virtual;  abstract;
  118.     function getAlignmentDate : tLinkDate; virtual;
  119.     procedure setAlignmentDate(avalue : tLinkDate); virtual;
  120.     function getChangeDate : TGregorianChangeRec; virtual;
  121.     procedure setChangeDate(avalue : TGregorianChangeRec); virtual;
  122.  
  123.     Property CalendarName : string read fName write fName;
  124.     Property OldCalendarSystemName : string read fNAmeOfPreviousSystem write fNameOfPreviousSystem;
  125.     Property ShowPreviousDatesInPreviousSystem : boolean read fSwitchOnChangeDate write fSwitchOnChangeDate;
  126. //    Property EncodeDateProc : tEncodeDateProc read fOnEncode write fOnEncode;
  127. //    Property DecodeDateProc : tDecodeDateProc read fOnDecode write fOnDecode;
  128. //    Property LeapYearRule : tLeapYearRule read fIsLeapYear write fIsLeapYear;
  129.     Property Astro : boolean read fAstro write fAstro default false;
  130.     Property DaysPerYear : cardinal read GetDaysPerYear; // write SetDaysPerYear;
  131.     Property NumberOfMonths : integer read getNumberOfMonths write setNumberOfMonths;
  132.     Property MonthName[index : integer] : string read getMonthName write setMonthName;
  133.     Property MonthLength[index : integer] : cardinal read getMonthLength write setMonthLength;
  134.     Property DayName[index : integer]: string read getDayName write setDayName;
  135.     Property DayStart: double read getDayStart write setDayStart;
  136.     Property AlignmentDate : tLinkDate read getAlignmentDate write setAlignmentDate;
  137.     Property ChangeDate : TGregorianChangeRec read getChangeDate write setChangeDate;
  138.     Property YearDef : tYearStructure read fYearDef;
  139.     //    Property DayOfWeek: integer read GetDayOfWeek;
  140.   Public
  141.     constructor create; virtual;
  142.     destructor destroy; override;
  143.     function GetDayOfWeek(MJD : tMJD) : integer; virtual;
  144.     Function IsLeapYear(aYear : integer): boolean; virtual; abstract;
  145.     Function EncodeDate(const aYear, aMonth, aDay :integer): tMJD; virtual;  abstract;
  146.     Function DecodeDate(const MJD : TMJD): tCalendarDate; virtual; abstract;
  147.     Function MSDatefromMJD(const MJD : TMJD): tDateTime; virtual; abstract;
  148.     Function MJDfromMSDate(const aDateTime : tDateTime): TMJD; virtual; abstract;
  149.    end;
  150.  
  151.   TEnglishCalendar = class(tCalendarDef)
  152.    Private
  153.      fSeptember1752,
  154.      fNormalSeptember : tMonthStructure;
  155.    Protected
  156.     function getDate : TLinkDate; override;
  157.     procedure setDate(aValue : tLinkDate); override;
  158. //    Property EncodeDateProc : tEncodeDateProc read fOnEncode write fOnEncode;
  159. //    Property DecodeDateProc : tDecodeDateProc read fOnDecode write fOnDecode;
  160. //    Property LeapYearRule : tLeapYearRule read fIsLeapYear write fIsLeapYear;
  161. //    Procedure fEncodeDate(var MJD : TMJD; const aYear, aMonth, aDay :integer); override;
  162. //    Procedure fDecodeDate(const MJD : TMJD; var aYear, aMonth, aDay :integer); override;
  163.   Public
  164.     Constructor create; override;
  165.     Destructor destroy; override;
  166.     Function IsLeapYear(aYear : integer): boolean; override;
  167.     Function EncodeDate(const aYear, aMonth, aDay :integer): tMJD; override;
  168.     Function DecodeDate(const MJD : TMJD): tCalendarDate; override;
  169.     Function MSDatefromMJD(const MJD : TMJD): tDateTime; override;
  170.     Function MJDfromMSDate(const aDateTime : tDateTime): TMJD; override;
  171.  
  172.     Property CalendarName;
  173.     Property OldCalendarSystemName;
  174.     Property ShowPreviousDatesInPreviousSystem;
  175.     Property Astro;
  176.     Property DaysPerYear;
  177.     Property NumberOfMonths;
  178.     Property MonthName;
  179.     Property MonthLength;
  180.     Property DayName;
  181.     Property DayStart;
  182.     Property AlignmentDate;
  183.     Property ChangeDate;
  184.     Property YearDef;
  185.     end;
  186.  
  187. Function ISOStdDateFormat(const ayear, aMonth, aDay : integer): integer;
  188.  
  189. implementation
  190.  
  191. Function ISOStdDateFormat(const ayear, aMonth, aDay : integer): integer;
  192. var temp : string;
  193. begin
  194.   temp := IntToStr(aYear)+format('%2.2d',[aMonth])+format('%2.2d',[aday]);
  195.   result := StrToInt(temp);
  196. end;
  197.  
  198.  
  199.  
  200. Function IsJulianLeapYear(const aYear : integer): boolean;
  201. begin
  202.   Result := (AYear mod 4 = 0);
  203. end;
  204.  
  205. function IsGregorianLeapYear(const AYear: Integer): Boolean;
  206. begin
  207.   Result := (AYear mod 4 = 0) and ((AYear mod 100 <> 0) or (AYear mod 400 = 0));
  208. end;
  209.  
  210. {=================  TMonthStructure ============================}
  211.  
  212. constructor tMonthStructure.BuildMonth(const aName : string; const aNumDays, StartMissing, EndMissing : integer);
  213. begin
  214.   inherited create;
  215.   fName := aName;
  216.   fNumDays := aNumDays;
  217.   fMissingDaysStart := StartMissing;
  218.   fMissingDaysEnd := EndMissing;
  219. end;
  220.  
  221. function TMonthStructure.HasMissingDays(var First, Last : integer): boolean;
  222. begin
  223.   if fMissingDaysStart = 0
  224.     then result := false
  225.     else begin
  226.       result := true;
  227.       First := fMissingDaysStart;
  228.       Last := fMissingDaysEnd;
  229.       end;
  230. end;
  231.  
  232. {=================== TYearStructure ===================}
  233.  
  234. constructor TYearStructure.create;
  235. var i : integer;
  236. begin
  237.   inherited create;
  238.   fMonthList := tlist.create;
  239.   fMonthList.capacity := 13;
  240.   for i := 1 to 13 do
  241.     fmonthList.add(nil);
  242. end;
  243.  
  244. destructor TYearStructure.destroy;
  245. var i : integer;
  246. begin
  247.   for i := 0 to fMonthList.count - 1 do
  248.     TMonthStructure(fMonthList.items[i]).free;
  249.   fMonthList.free;
  250.   inherited destroy;
  251. end;
  252.  
  253. procedure tYearStructure.growMonthList;
  254. begin
  255.   fMonthList.add(nil);
  256.   fMonthList.add(nil);
  257. end;
  258.  
  259. {Procedure TYearStructure.SwapMonths(index : integer; var WithMonth : tMonthStructure);
  260. var temp : tMonthStructure;
  261. begin
  262.   if fMonthList.capacity < index then GrowMonthList;
  263.   temp := MonthObj[index];
  264.   fMonthList.items[index-1] := nil;
  265.   MonthObj[index] := WithMonth;
  266.   WithMonth := temp;
  267. end;}
  268.  
  269. function TYearStructure.GetMonthName(index : integer): string;
  270. var offset : integer;
  271. begin
  272.   offset := index-1;
  273.   result := TMonthStructure(fMonthList.items[offset]).name;
  274. end;
  275.  
  276. procedure TYearStructure.SetMonthName(index : integer; aName : string);
  277. var offset : integer;
  278. begin
  279.   if fMonthList.capacity < index then GrowMonthList;
  280.   offset := index - 1;
  281.   TMonthStructure(fMonthList.items[offset]).name := aName;
  282. end;
  283.  
  284. function TYearStructure.GetMonthLen(index : integer): integer;
  285. var offset : integer;
  286. begin
  287.   offset := index-1;
  288.   result := TMonthStructure(fMonthList.items[offset]).numdays;
  289. end;
  290.  
  291. procedure TYearStructure.SetMonthLen(index : integer; aLen : integer);
  292. var offset : integer;
  293. begin
  294.   if fMonthList.capacity < index then GrowMonthList;
  295.   offset := index - 1;
  296.   TMonthStructure(fMonthList.items[offset]).NumDays := aLen;
  297. end;
  298.  
  299. function TYearStructure.GetMonthStruc(index : integer): tMonthStructure;
  300. var offset : integer;
  301. begin
  302.   offset := index-1;
  303.   result := TMonthStructure(fMonthList.items[offset]);
  304. end;
  305.  
  306. procedure TYearStructure.setMonthStruc(index : integer; aStruc : tMonthStructure);
  307. var offset : integer;
  308. begin
  309.   if fMonthList.capacity < index then GrowMonthList;
  310.   offset := index - 1;
  311.   if fMonthList.items[offset] <> nil
  312.     then fMonthList.items[offset] := nil;
  313.   fMonthList.items[offset] := astruc;
  314. end;
  315.  
  316.  
  317.  
  318. {=============== TCalendarDef ==================}
  319.  
  320. Constructor TCalendarDef.Create;
  321. begin
  322.   inherited create;
  323.   fYearDef := TYearStructure.create;
  324.   fDayName := tstringlist.create;
  325. end;
  326.  
  327. Destructor TCalendarDef.destroy;
  328. begin
  329.   fYearDef.free;
  330.   fDayName.free;
  331.   inherited destroy;
  332. end;
  333.  
  334. function TCalendarDef.getDate : TLinkDate;
  335. begin result := fDate end;
  336.  
  337. procedure TCalendarDef.setDate(avalue : tLinkDate);
  338. begin fDate := avalue; end;
  339.  
  340. function TCalendarDef.getDaysPerYear : cardinal;
  341. var i : integer;
  342. begin
  343.   result := 0;
  344.   for i := 1 to fYearDef.NumMonths do
  345.      result := result + fYearDef.MonthLen[i];
  346. end;
  347.  
  348. //procedure TCalendarDef.setDaysPerYear(avalue : cardinal);
  349. //begin  fDaysPerYear := avalue end;
  350.  
  351. function TCalendarDef.getNumberOfMonths : integer;
  352. begin result := fYearDef.NumMonths; end; //MonthNameLength.count; end;
  353.  
  354. procedure TCalendarDef.setNumberOfMonths(avalue : integer);
  355. begin  fYearDef.NumMonths := aValue; end; //MonthNameLength.capacity := aValue end;
  356.  
  357. function TCalendarDef.getMonthName(index: integer): string;
  358. begin
  359.   if (index < fYearDef.NumMonths) and (index > 0)
  360.     then result := fYearDef.MonthName[index]
  361.     else raise EMonthList.create(format(cNoSuchMonthIndex, [index]));
  362. end;
  363.  
  364. procedure TCalendarDef.setMonthName(index : integer; aName : string);
  365. begin
  366.   if (index < fYearDef.NumMonths) and (index > 0)
  367.     then fYEarDef.MonthName[index] := aName
  368.     else raise EMonthList.create(format(cNoSuchMonthIndex, [index]));
  369. end;
  370.  
  371. function TCalendarDef.getMonthLength(index : integer): cardinal;
  372. begin
  373.   if (index < fYearDef.NumMonths) and (index > 0)
  374.     then result := fYearDef.MonthLen[index] //LongInt(fMonthNameLength.objects[index])
  375.     else raise EMonthList.create(format(cNoSuchMonthIndex, [index]));
  376. end;
  377.  
  378. procedure TCalendarDef.setMonthLength(index : integer; aValue : cardinal);
  379. begin
  380.   if (index < fYearDef.NumMonths) and (index > 0)
  381.     then fYearDef.MonthLen[index] := aValue //fMonthNameLength.objects[index] := Ptr(index)
  382.     else raise EMonthList.create(format(cNoSuchMonthIndex, [index]));
  383. end;
  384.  
  385. function TCalendarDef.getDayName(index : integer): string;
  386. begin
  387.   if (index < fDayName.count) and (index > -1)
  388.     then result := fDayName[index]
  389.     else raise EDayList.create(format(cNoSuchDayIndex, [index]));
  390. end;
  391.  
  392. procedure TCalendarDef.setDayName(index : integer; aName : string);
  393. begin
  394.   if (index < fDayName.count) and (index > -1)
  395.     then fDayName[index] := aName
  396.     else raise EDayList.create(format(cNoSuchDayIndex, [index]));
  397. end;
  398.  
  399. function TCalendarDef.getDayStart: double;
  400. begin result := fDayStart end;
  401.  
  402. procedure TCalendarDef.setDayStart(avalue : double);
  403. begin fDayStart := avalue end;
  404.  
  405. function TCalendarDef.getAlignmentDate : tLinkDate;
  406. begin result := falignmentDate end;
  407.  
  408. procedure TCalendarDef.setAlignmentDate(avalue : tLinkDate);
  409. begin fAlignmentDate := avalue; end;
  410.  
  411. function tCalendarDef.getChangeDate : TGregorianChangeRec;
  412. begin result := fGregorianDate; end;
  413.  
  414. procedure tCalendarDef.setChangeDate(avalue : TGregorianChangeRec);
  415. begin fGregorianDate := aValue; end;
  416.  
  417. Function tCalendarDef.GetDayOfWeek(MJD : tMJD): integer;
  418. begin
  419.   result := (trunc(MJD)+999999990) mod 7 +1;
  420. //  trunc(mjd) mod 7; // + 1;
  421. end;  
  422.  
  423. {================= English Calendar ==================}
  424.  
  425. const
  426.   cEnglishLinkDate : tLinkDate = (Date: (year: 1995; month : 10; day: 10); MJD: 50000);
  427.   cEnglishChangeDate : tGregorianChangeRec = (LastMJD : cLastMJDEnglish; LastDate: (year: 1752; month: 9; day: 13); Adjustment: 11);
  428.   cNormalMonthLengths : array[1..12] of integer = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  429.  
  430. Constructor TEnglishCalendar.create;
  431. var i : integer;
  432. begin
  433.   inherited create;
  434.   SetAlignmentDate(cEnglishLinkDate);
  435.   SetChangeDate(cEnglishChangeDate);
  436.   FYearDef.NumMonths := 12;
  437.   for i := 1 to 12 do
  438.     FYearDef.MonthObj[i] := tMonthStructure.buildMonth(longMonthNames[i], cNormalMonthLengths[i], 0, 0);
  439.   fSeptember1752 := tMonthStructure.buildMonth(LongmonthNames[9], 19, 3, 13);
  440.   fNormalSeptember := tMonthStructure.buildMonth(LongmonthNames[9], 30,0,0);
  441.   for i := 1 to 7 do
  442.     FDayName.add(LongDayNames[i]);
  443.   fSwitchOnChangeDate := true;
  444.   fNameOfPreviousSystem := 'Julian';
  445.   fName := 'English';
  446. end;
  447.  
  448. Destructor TEnglishCalendar.destroy;
  449. begin
  450.   inherited destroy;
  451. end;
  452.  
  453. Function TEnglishCalendar.IsLeapYear(aYear : integer): boolean;
  454. begin
  455.   if ShowPreviousDatesInPreviousSystem
  456.     then begin
  457.       if aYear < ChangeDate.LastDate.year
  458.         then result := IsJulianLeapYear(aYear)
  459.         else result := IsGregorianLeapYear(aYEar);
  460.       if AYear = ChangeDate.LastDate.Year
  461.            then fYearDef.MonthObj[9] := fSeptember1752
  462.            else fYearDef.MonthObj[9] := fNormalSeptember;
  463.       end
  464.     else result := IsGregorianLeapYear(aYear);
  465.   if result
  466.     then fYearDef.MonthLen[2] := 29
  467.     else fYearDef.MonthLen[2] := 28;  //fMonthNameLength.objects[1] := ptr(28);
  468. end;
  469.  
  470. Function TEnglishCalendar.EncodeDate(const aYear, aMonth, aDay :integer): tMJD;
  471. // aMonth is 1..12, aDay is 1..31
  472. // this code is more or less a direct translation of Stockton's code in MJD_DATE.PAS
  473. var iMJD : integer;
  474.     ThisYear, ThisMonth : integer;
  475.     J : byte;
  476.   procedure Steps(const D, Y : longint); // Increase MJDy by steps of D per Y Years
  477.   var x : integer;
  478.   begin
  479.     X := ThisYear div Y;
  480.     Inc(iMJD, X*D);
  481.     ThisYear := ThisYear mod Y;
  482.   end;
  483. begin
  484.   IsLeapYear(aYear);
  485.   if ShowPreviousDatesInPreviousSystem
  486.     then if AYear = ChangeDate.LastDate.Year
  487.            then begin
  488.              fYearDef.MonthObj[9] := fSeptember1752;
  489.              if (aMonth = 9) and (aDay in [3..13])
  490.                 then raise eChangeOverError.create(c1752IsChangeOver);
  491.              end
  492.            else fYearDef.MonthObj[9] := fNormalSeptember;
  493. //  if (aday < 1) or (aday > fYearDef.MonthObj[aMonth].fNumDays)
  494. //    then raise eDayOutOfMonthRange.create(cDayOutOfMonthRange);
  495.   if (aMonth < 1) or (aMonth > fYearDef.NumMonths)
  496.     then raise eMonthOutOfYearRange.create(cMonthOutOfYearRange);
  497.   ThisMonth := aMonth;
  498.   ThisYear := aYear;
  499.   if aMonth < cBaseMo
  500.     then begin
  501.       Inc(ThisMonth, 12);
  502.       Dec(ThisYear);
  503.       end;
  504.   if not Astro
  505.     then if ThisYear < 1 then Inc(ThisYear) { No Year Zero } ;
  506.   if (ThisYear < cBaseYr)
  507.     then Raise eOutOfYEarRange.create(format(cOutOfYearRange, [abs(cBaseYr),abs(cBaseYr)]));
  508.   ThisYear := ThisYear - cBaseYr ;
  509.   if ShowPreviousDatesInPreviousSystem
  510.     then If ISOStdDateFormat(aYear,aMonth,aday)
  511.              < ISOStdDateFormat(ChangeDate.LastDate.Year, ChangeDate.LastDate.Month, ChangeDate.lastdate.day)
  512.            then iMJD := -cJulnBias
  513.            else begin
  514.              iMJD := -cGregBias;
  515.              Steps(cYrs400, 400) ;
  516.              Steps(cYrs100, 100)
  517.              end ;
  518.   Steps(cYrs004,   4) ;
  519.   Inc(iMJD, ThisYear*cYrs001) ;
  520.   for J := cBaseMo to Pred(ThisMonth) do
  521.     Inc(iMJD, cSpecialMonthsArray[J]);
  522.   Result := iMJD + aDay;
  523. end;
  524.  
  525. Function TEnglishCalendar.DecodeDate(const MJD : TMJD): tCalendarDate;
  526. (*
  527. // this code is derived from the example on page 13 of Numerical Recipes in Pascal
  528. // and comes out 1 day too late...
  529. var PureJ : integer;
  530.     je, jd, jc, jb, jalpha, ja : integer;
  531. const igreg = 2299161;
  532. begin
  533.   PureJ := trunc(MJD + cJDoffset);
  534.   if pureJ >= igreg
  535.     then begin
  536.       jalpha := trunc(((PureJ - 1867216)-0.25)/36524.25);
  537.       ja := PureJ + 1 + jalpha - trunc(0.25*jalpha);
  538.       end
  539.     else ja := PureJ;
  540.   jb := ja + 1524;
  541.   jc := trunc(6680.0+((jb-2439870)-122.1)/365.25);
  542.   jd := 365*jc + trunc(0.25*jc);
  543.   je := trunc((jb-jd) / 30.6001);
  544.   result.day := jb - jd - trunc(30.6001 * je);
  545.   result.month := je - 1;
  546.   if result.month > 12
  547.     then result.month := Result.month - 12;
  548.   result.year := jc - 4715;
  549.   if result.month > 2
  550.     then result.year := result.year - 1;
  551.   if result.year <= 0  // astro adjustment
  552.      then result.year := result.year -1;
  553. end;
  554. *)
  555. //this was my attempt to translate Stockton's code.  It gave me the correct year,
  556. //but the month and day were way off.
  557. var ThisYear, ThisMonth, thisDay : integer;
  558.     iMJD : integer;
  559.     T : longint ;
  560.   // procedure YMDW(Cal : Calendar ; As : boolean ; MJDy : longint ;
  561.   //  var Yr : integer ; var Mo, Dy : byte)
  562.   procedure Moves(const D, Y, N : longint); // Reduce MJDy by up to N steps of D, counting in Yr
  563.   var X : longint ;
  564.   begin
  565.     X := Pred(iMJD) div D;
  566.     if X>N then Dec(X); { X:=N ? }
  567.     Inc(ThisYear, X*Y);
  568.     iMJD := iMJD - X*D
  569.   end;
  570.  
  571. begin
  572. {  if Cal=Civil then
  573.     if MJDy>LastJulianMJD[ChangeD] then Cal := Gregorian else Cal := Julian ;
  574.   Inc(MJDy, Bias[Cal]) ;}
  575.   if ShowPreviousDatesInPreviousSystem
  576.     then begin
  577.       if MJD > cLastMJDEnglish
  578.         then iMJD := Trunc(MJD) + cGregBias
  579.         else iMJD := Trunc(MJD) + cJulnBias;
  580.       end
  581.     else iMJD := Trunc(MJD) + cGregBias;
  582. {  if MJDy>longint(2)*(-BaseYr)*Succ(Yrs001) then InputError(232) ;}
  583.   if (iMJD < 1) or (abs(iMJD) > 2*abs(cBaseYr)*Succ(cYrs001))
  584.     then raise eOutOfMJDRange.create(format(cOutOfMJDRange, [1.0, 1.0*abs(cBaseYr)*Succ(cYrs001)]));
  585.   ThisYear := cBaseYr;
  586.   ThisMonth := cBaseMo;
  587.   if MJD > cLastMJDEnglish
  588.     then begin
  589.       Moves(cYrs400, 400, MaxLongInt) ;
  590.       Moves(cYrs100, 100, 3)
  591.       end ;
  592.   Moves(cYrs004,   4, MaxLongInt) ;
  593.   Moves(cYrs001,   1, 3);
  594.   // ThisYear close enough, now work on month
  595.   // but I can't figure out what he's doing here...
  596.   repeat
  597.     T := iMJD - cSpecialMonthsArray[ThisMonth];
  598.     if T < 1 then BREAK ;
  599.     iMJD := T ;
  600.     Inc(ThisMonth)
  601.     until ThisMonth = cUltiMo;  {Feb is long enough} {but array isn' that big?}
  602.   ThisDay := iMJD;
  603.   if ThisMonth > 12
  604.     then begin
  605.       Dec(ThisMonth, 12);
  606.       Inc(ThisYear)
  607.       end;
  608.   if not Astro then if ThisYear < 1 then Dec(ThisYear) { No Year Zero } ;
  609.   IsLeapYear(ThisYear);  // make sure fYearDef has right months...
  610.   result.year := ThisYear;
  611.   result.month := ThisMonth;
  612.   result.day := ThisDay;
  613. end;
  614.  
  615. Function TEnglishCalendar.MSDatefromMJD(const MJD : TMJD): tDateTime;
  616. begin
  617.   result := Trunc(MJD) - cMJD10Oct1995 + cMS10Oct1995;
  618.   if (result < cLowerTDateTime) or (result > cUpperTDateTime)
  619.     then raise EMJDOutsideTDateTimeRange.create(cMJDOutsideTDateTimeRange);
  620. end;
  621.  
  622. Function TEnglishCalendar.MJDfromMSDate(const aDateTime : tDateTime): TMJD;
  623. begin
  624.   result := Trunc(aDateTime) - cMS10Oct1995;
  625.   result := result + cMJD10Oct1995;
  626. end;
  627.  
  628. function TEnglishCalendar.getDate : TLinkDate;
  629. begin
  630.   result := fAlignmentDate;
  631. end;
  632.  
  633. procedure TEnglishCalendar.setDate(aValue : tLinkDate);
  634. begin
  635.  
  636. end;
  637.  
  638.  
  639.  
  640. end.
  641.